package com.roads.engineering.service.impl;

import com.roads.common.config.MasterConfig;
import com.roads.common.constant.Constants;
import com.roads.common.utils.StringUtils;
import com.roads.common.utils.file.FileUtils;
import com.roads.engineering.constant.PaymentConstant;
import com.roads.engineering.domain.EngMeterageContract;
import com.roads.engineering.domain.EngMeterageOther;
import com.roads.engineering.domain.summary.SummaryBoq;
import com.roads.engineering.domain.summary.SummaryBoqMeterage;
import com.roads.engineering.domain.summary.SummaryIpc;
import com.roads.engineering.domain.summary.SummaryRecord;
import com.roads.engineering.domain.summary.SummaryRecordUserVo;
import com.roads.engineering.domain.summary.SummaryVo;
import com.roads.engineering.mapper.EngMeterageContractMapper;
import com.roads.engineering.mapper.EngMeterageOtherMapper;
import com.roads.engineering.mapper.SummaryBoqMapper;
import com.roads.engineering.mapper.SummaryBoqMeterageMapper;
import com.roads.engineering.mapper.SummaryIpcMapper;
import com.roads.engineering.mapper.SummaryRecordMapper;
import com.roads.engineering.service.ISummaryService;
import com.roads.project.domain.ProBoq;
import com.roads.project.domain.ProBoqMeterage;
import com.roads.project.domain.ProInstitution;
import com.roads.project.domain.ProInstitutionDetail;
import com.roads.project.domain.ProPaymentItems;
import com.roads.project.mapper.ProBoqMapper;
import com.roads.project.mapper.ProInstitutionDetailMapper;
import com.roads.project.mapper.ProInstitutionMapper;
import com.roads.project.mapper.ProPaymentItemsMapper;
import com.roads.project.mapper.ProPeriodMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName SummaryServiceImpl
 * @Description 汇总service实现类
 * @Author nhp
 * @Date 2022/5/5 0005 14:28
 * @Version 1.0.0
 **/
@Service
public class SummaryServiceImpl implements ISummaryService {

    @Autowired
    private SummaryRecordMapper summaryRecordMapper;

    @Autowired
    private SummaryBoqMapper summaryBoqMapper;

    @Autowired
    private SummaryIpcMapper summaryIpcMapper;

    @Autowired
    private SummaryBoqMeterageMapper summaryBoqMeterageMapper;

    @Autowired
    private ProInstitutionMapper institutionMapper;

    @Autowired
    private ProInstitutionDetailMapper institutionDetailMapper;

    @Autowired
    private ProBoqMapper boqMapper;

    @Autowired
    private EngMeterageContractMapper meterageContractMapper;

    @Autowired
    private EngMeterageOtherMapper meterageOtherMapper;

    @Autowired
    private ProPaymentItemsMapper paymentItemsMapper;

    @Autowired
    private ProPeriodMapper periodMapper;

    /**
     * 获取汇总记录
     *
     * @param summaryRecord
     * @return
     */
    @Override
    public SummaryRecord getSummaryRecord(SummaryRecord summaryRecord) {
        return summaryRecordMapper.getSummaryRecord(summaryRecord.getCreateBy(), summaryRecord.getInstitutionCode(), summaryRecord.getPeriodName());
    }

    /**
     * 根据机构编号，工期获取汇总用户集合
     *
     * @param institutionCode 机构编号
     * @param periodName 工期
     * @return 汇总用户集合
     */
    @Override
    public List<SummaryRecordUserVo> selectSummaryRecordUserList(String institutionCode, String periodName) {
        return summaryRecordMapper.selectSummaryRecordUserList(institutionCode, periodName);
    }

    /**
     * 查看汇总是否批复
     *
     * @param institutionCode 机构编号
     * @param periodName 工期
     * @return 是否批复
     */
    @Override
    public boolean getSummaryIsApprove(String institutionCode, String periodName) {
        SummaryRecord summaryRecord = summaryRecordMapper.getSummaryRecordIsApprove(institutionCode, periodName);
        return StringUtils.isNotNull(summaryRecord);
    }

    /**
     * 获取汇总批复记录
     *
     * @param institutionCode 机构编号
     * @param periodName 工期
     * @return 汇总记录
     */
    @Override
    public SummaryRecord getSummaryRecordByApprove(String institutionCode, String periodName) {
        return summaryRecordMapper.getSummaryRecordIsApprove(institutionCode, periodName);
    }

    /**
     * 获取汇总记录最后汇总用户
     *
     * @param institutionCode 机构编号
     * @param periodName 工期
     * @return 汇总用户
     */
    @Override
    public String getSummaryLastUser(String institutionCode, String periodName) {
        return summaryRecordMapper.getSummaryLastUser(institutionCode, periodName);
    }

    /**
     * 根据标段编号/工期/支付项目编号获取某支付项目
     *
     * @param institutionCode 标段编号
     * @param periodName 工期
     * @param userName 用户
     * @param itemCode 支付项目编号
     * @return 某支付项目
     */
    @Override
    public SummaryIpc getItemByBidAndPeriodAndItemCode(String institutionCode, String periodName, String userName, String itemCode) {
        return summaryIpcMapper.getItemByBidAndPeriodAndItemCode(institutionCode, periodName, userName, itemCode);
    }

    /**
     * 根据项目ID获取项目百章各期本期末完成金额
     *
     * @param projectId 项目ID
     * @return 百章项目各期值
     */
    @Override
    public List<SummaryIpc> getProjectHundredChaptersCurrentEndTotalByProject(Integer projectId) {
        return summaryIpcMapper.getProjectHundredChaptersCurrentEndTotalByProject(projectId);
    }

    /**
     * 根据项目ID/用户获取项目百章各期本期末完成金额
     *
     * @param projectId 项目ID
     * @param userName 用户
     * @return 百章项目各期值
     */
    @Override
    public List<SummaryIpc> getProjectHundredChaptersCurrentEndTotalByProjectAndUser(Integer projectId, String userName) {
        return summaryIpcMapper.getProjectHundredChaptersCurrentEndTotalByProjectAndUser(projectId, userName);
    }

    /**
     * 查询当前登录用户在计量流程节点出现的次数
     * @param user 当前登录用户
     * @return 数量
     */
    @Override
    public int getCountWorkflowNodeUser(String user) {
        return summaryRecordMapper.getCountWorkflowNodeUser(user);
    }

    /**
     * 数据汇总
     *
     * @param model 汇总实体对象
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int summary(SummaryVo model) {
        long startTime = System.currentTimeMillis();
        // 1.设置属性
        setAttribute(model);
        // 2.汇总记录
        summaryRecord(model);
        // 3.汇总工程量清单
        List<SummaryBoq> summaryBoqList = new ArrayList<>();
        Map<String, SummaryBoq> hundredItemMap = new HashMap<>();
        Map<String, SummaryBoq> leafNodeItemMap = new HashMap<>();
        summaryBoq(model, summaryBoqList, hundredItemMap, leafNodeItemMap);
        // 4.汇总工程计量清单
        summaryBoqMeterage(model, leafNodeItemMap);
        // 5.汇总中期支付证书
        summaryIpc(model, hundredItemMap, summaryBoqList);
        long endTime = System.currentTimeMillis();
        System.out.println("汇总方法耗时：" + (endTime - startTime) + " ms");
        System.out.println(model.toString());
        return 1;
    }

    /**
     * 1.设置属性
     * ①设置清单的标段编号，如果标段类型是分部，并且共享父项清单，需要将标段设置成父项标段编号
     * ②设置上一其次
     *
     * @param model
     */
    public void setAttribute(SummaryVo model) {
        long startTime = System.currentTimeMillis();
        // 设置清单标段编号
        ProInstitution institution = institutionMapper.getModelByInnerCode(model.getInstitutionCode());
        // 设置报表编号
        if (StringUtils.isNotEmpty(institution.getReportCode())) {
            model.setReportCode(institution.getReportCode());
        } else {
            model.setReportCode(institution.getInstitutionCode());
        }
        if (institution.getInstitutionType().equals(Constants.INSTITUTION_TYPE_F)) {
            ProInstitution parent = institutionMapper.getModelByInnerCode(institution.getParentCode());
            if (parent.getIsShare().equals(Constants.YES)) {
                model.setBoqInstitutionCode(parent.getInnerCode());
            } else {
                model.setBoqInstitutionCode(model.getInstitutionCode());
            }
        } else {
            model.setBoqInstitutionCode(model.getInstitutionCode());
        }
        // 设置上一期
        String lastPeriodName = String.valueOf(Integer.parseInt(model.getPeriodName()) - 1);
        model.setLastPeriodName(lastPeriodName);
        // 设置上一期批复用户
        if (!"0".equals(model.getLastPeriodName())) {
            SummaryRecord summaryRecord = summaryRecordMapper.getSummaryRecordIsApprove(model.getInstitutionCode(), model.getLastPeriodName());
            if (StringUtils.isNotNull(summaryRecord)) {
                model.setApproveUser(summaryRecord.getCreateBy());
            } else {
                model.setApproveUser(model.getUserName());
            }
        }
        // 设置工期零填充
        if (Integer.parseInt(model.getPeriodName()) < 10) {
            model.setPeriodNameZeroFilling("0" + model.getPeriodName());
        }
        // 重置当前其次
        resetCurrentPeriod(model);
        long endTime = System.currentTimeMillis();
        System.out.println("重置标段编号耗时：" + (endTime - startTime) + " ms");
    }

    /**
     * 重置当前期次
     *
     * @param model 汇总实体对象
     */
    private void resetCurrentPeriod(SummaryVo model) {
        // 最终批复，需要将当前期次更改为下一期
        if (Constants.YES.equals(model.getIsApprove())) {
            // 设置下一期为当前计量期次
            String nextPeriodName = String.valueOf(Integer.parseInt(model.getPeriodName()) + 1);
            periodMapper.updateCurrentMeteragePeriod(model.getInstitutionCode(), nextPeriodName);
            // 设置除下一期以外期次为非当前计量期次
            periodMapper.updateNotCurrentMeteragePeriod(model.getInstitutionCode(), nextPeriodName);
            // 设置本期为锁定状态
            periodMapper.lockPeriod(model.getInstitutionCode(), model.getPeriodName());
        } else {
            // 判断是否为解锁操作
            SummaryRecord summaryRecord = summaryRecordMapper.getSummaryRecord(model.getUserName(), model.getInstitutionCode(), model.getPeriodName());
            // 查看以前是否汇总过，如果汇总过，并且是批复汇总，并且本次汇总为非汇总批复，视为解锁操作
            if (StringUtils.isNotNull(summaryRecord)
                    && Constants.YES.equals(summaryRecord.getIsApprove())
                    && Constants.NO.equals(model.getIsApprove())) {
                // 设置本期为当前计量期次
                periodMapper.updateCurrentMeteragePeriod(model.getInstitutionCode(), model.getPeriodName());
                // 设置除本期以外期次为非当前计量期次
                periodMapper.updateNotCurrentMeteragePeriod(model.getInstitutionCode(), model.getPeriodName());
                // 设置本期为非锁定状态
                periodMapper.unlockPeriod(model.getInstitutionCode(), model.getPeriodName());
            }
        }
    }

    /**
     * 2.汇总记录表
     *
     * @param model 汇总实体对象
     */
    private void summaryRecord(SummaryVo model) {
        long startTime = System.currentTimeMillis();
        SummaryRecord summaryRecord = summaryRecordMapper.getSummaryRecord(model.getUserName(), model.getInstitutionCode(), model.getPeriodName());
        if (StringUtils.isNotNull(summaryRecord)) {
            // 修改汇总记录
            summaryRecord.setInstitutionCode(model.getInstitutionCode());
            summaryRecord.setPeriodName(model.getPeriodName());
            summaryRecord.setIsApprove(model.getIsApprove());
            summaryRecord.setCreateBy(model.getUserName());
            summaryRecord.setCreateTime(model.getSummaryDate());
            summaryRecordMapper.update(summaryRecord);
        } else {
            summaryRecord = new SummaryRecord();
            summaryRecord.setInstitutionCode(model.getInstitutionCode());
            summaryRecord.setPeriodName(model.getPeriodName());
            summaryRecord.setIsApprove(model.getIsApprove());
            summaryRecord.setCreateBy(model.getUserName());
            summaryRecord.setCreateTime(model.getSummaryDate());
            summaryRecordMapper.insert(summaryRecord);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("汇总记录耗时：" + (endTime - startTime) + " ms");
    }

    /**
     * 3.汇总工程量清单
     *
     * @param model 汇总实体对象
     * @param summaryBoqList 汇总清单集合
     * @param hundredItemMap 百章清单集合
     * @param leafNodeItemMap 叶子节点清单集合
     */
    private void summaryBoq(SummaryVo model, List<SummaryBoq> summaryBoqList, Map<String, SummaryBoq> hundredItemMap, Map<String, SummaryBoq> leafNodeItemMap) {
        long startTime = System.currentTimeMillis();
        // 删除数据
        summaryBoqMapper.deleteSummaryBoq(model.getUserName(), model.getInstitutionCode(), model.getPeriodName());
        // 获取标段工程量清单
        ProBoq boqSearch = new ProBoq();
        boqSearch.setInstitutionCode(model.getBoqInstitutionCode());
        List<ProBoq> boqList = boqMapper.selectProBoqList(boqSearch);
        // 获取标段计量清单
        List<ProBoq> childrenSumList = boqMapper.sumListByInstitutionCode(model.getBoqInstitutionCode());
        // 重新汇总 核算 符合数量和符合金额，变更数量和变更金额
        // 转成map对象
        Map<String, ProBoq> sumMap = new HashMap<>(childrenSumList.size());
        for (ProBoq boq : childrenSumList) {
            sumMap.put(boq.getInstitutionBoqCode(), boq);
        }
        // 3.1 重新计算工程量清单符合数量和金额
        againSummaryBoq(boqList, sumMap, childrenSumList);
        // 3.2 初始化汇总工程量清单
        initSummaryBoq(summaryBoqList, boqList, model);
        // 3.3 更新汇总工程量清单 更新上期末数量、金额，本期数量、金额，本期末数量、金额
        updateSummaryBoq(summaryBoqList, model, hundredItemMap, leafNodeItemMap);
        // 批量插入数据库
        summaryBoqMapper.insertBatch(summaryBoqList);
        long endTime = System.currentTimeMillis();
        System.out.println("汇总工程量清单耗时：" + (endTime - startTime) + " ms");
    }

    /**
     * 3.1 重新计算工程量清单符合数量和金额
     *
     * @param boqList 工程量清单
     * @param sumMap 合计的计量清单转map
     * @param childrenSumList 合计的计量清单
     */
    private void againSummaryBoq(List<ProBoq> boqList, Map<String, ProBoq> sumMap, List<ProBoq> childrenSumList) {
        long startTime = System.currentTimeMillis();
        // 循环处理
        for (ProBoq boq: boqList) {
            if (Constants.YES.equals(boq.getLeafNode())) {
                String institutionBoqCode = boq.getInstitutionBoqCode();
                ProBoq sumBoq = sumMap.get(institutionBoqCode);
                if (StringUtils.isNotNull(sumBoq)) {
                    boq.setReviewAmount(sumBoq.getReviewAmount());
                    BigDecimal sumReviewTotal = sumBoq.getReviewTotal() == null ?
                            BigDecimal.ZERO : sumBoq.getReviewTotal().setScale(boq.getDecimalPlace(), BigDecimal.ROUND_HALF_UP);
                    boq.setReviewTotal(sumReviewTotal);
                    boq.setChangeAmount(sumBoq.getChangeAmount());
                    BigDecimal sumChangeTotal = sumBoq.getChangeTotal() == null ?
                            BigDecimal.ZERO : sumBoq.getChangeTotal().setScale(boq.getDecimalPlace(), BigDecimal.ROUND_HALF_UP);
                    boq.setChangeTotal(sumChangeTotal);
                }
            } else {
                String boqCode = boq.getBoqCode() + ",";
                BigDecimal amount = BigDecimal.valueOf(0);
                BigDecimal total = BigDecimal.valueOf(0);
                BigDecimal reviewAmount = BigDecimal.valueOf(0);
                BigDecimal reviewTotal = BigDecimal.valueOf(0);
                BigDecimal changeAmount = BigDecimal.valueOf(0);
                BigDecimal changeTotal = BigDecimal.valueOf(0);
                for (ProBoq sumBoq: childrenSumList) {
                    String ancestors = sumBoq.getAncestors();
                    // 因800章清单问题导致其他大类会统计到800章的清单，所以这里进行一个前缀判断，保证清单是同一个大类
                    String boqPrefix = boq.getAncestors().substring(0, 3);
                    String sumBoqPrefix = sumBoq.getAncestors().substring(0, 3);
                    if (ancestors.contains(boqCode) && boqPrefix.equals(sumBoqPrefix)) {
                        if (sumBoq.getTotal() != null) {
                            total = total.add(sumBoq.getTotal());
                        }
                        if (sumBoq.getReviewTotal() != null) {
                            BigDecimal sumReviewTotal = sumBoq.getReviewTotal() == null ?
                                    BigDecimal.ZERO : sumBoq.getReviewTotal().setScale(boq.getDecimalPlace(), BigDecimal.ROUND_HALF_UP);
                            reviewTotal = reviewTotal.add(sumReviewTotal);
                        }
                        if (sumBoq.getChangeTotal() != null) {
                            BigDecimal sumChangeTotal = sumBoq.getChangeTotal() == null ?
                                    BigDecimal.ZERO : sumBoq.getChangeTotal().setScale(boq.getDecimalPlace(), BigDecimal.ROUND_HALF_UP);
                            changeTotal = changeTotal.add(sumChangeTotal);
                        }
                    }
                }
                boq.setAmount(amount.equals(BigDecimal.valueOf(0)) ? null : amount);
                boq.setTotal(total.equals(BigDecimal.valueOf(0)) ? null : total);
                boq.setReviewAmount(reviewAmount.equals(BigDecimal.valueOf(0)) ? null : reviewAmount);
                boq.setReviewTotal(reviewTotal.equals(BigDecimal.valueOf(0)) ? null : reviewTotal);
                boq.setChangeAmount(changeAmount.equals(BigDecimal.valueOf(0)) ? null : changeAmount);
                boq.setChangeTotal(changeTotal.equals(BigDecimal.valueOf(0)) ? null : changeTotal);
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("3.1 重新计算工程量清单符合数量和金额耗时：" + (endTime - startTime) + " ms");
    }

    /**
     * 3.2 初始化汇总工程量清单
     * @param summaryBoqList 汇总工程量清单集合
     * @param boqList 工程量清单集合
     * @param model 汇总实体对象
     */
    private void initSummaryBoq(List<SummaryBoq> summaryBoqList, List<ProBoq> boqList, SummaryVo model) {
        long startTime = System.currentTimeMillis();
        for (ProBoq boq: boqList) {
            SummaryBoq summaryBoq = new SummaryBoq();
            summaryBoq.setInstitutionCode(model.getInstitutionCode());
            summaryBoq.setPeriodName(model.getPeriodName());
            summaryBoq.setInstitutionBoqCode(boq.getInstitutionBoqCode());
            summaryBoq.setBoqCode(boq.getBoqCode());
            summaryBoq.setBoqName(boq.getBoqName());
            summaryBoq.setParentCode(boq.getParentCode());
            summaryBoq.setAncestors(boq.getAncestors());
            summaryBoq.setOrderNum(boq.getOrderNum());
            summaryBoq.setLevel(boq.getLevel());
            summaryBoq.setLeafNode(boq.getLeafNode());
            summaryBoq.setUnit(boq.getUnit());
            summaryBoq.setPrice(boq.getPrice());
            summaryBoq.setAmount(boq.getAmount());
            summaryBoq.setTotal(boq.getTotal());
            summaryBoq.setReviewPrice(boq.getReviewPrice());
            summaryBoq.setReviewAmount(boq.getReviewAmount());
            summaryBoq.setReviewTotal(boq.getReviewTotal());
            summaryBoq.setChangePrice(boq.getChangePrice());
            BigDecimal changeAmount = boq.getChangeAmount() == null ? new BigDecimal(0) : boq.getChangeAmount();
            BigDecimal changeTotal = boq.getChangeTotal() == null ? new BigDecimal(0) : boq.getChangeTotal();
            summaryBoq.setChangeAmount(changeAmount);
            summaryBoq.setChangeTotal(changeTotal);
            summaryBoq.setDecimalPlace(boq.getDecimalPlace());
            // 变更后金额和数量
            BigDecimal amount = boq.getReviewAmount() == null ? new BigDecimal(0) : boq.getReviewAmount();
            BigDecimal total = boq.getReviewTotal() == null ? new BigDecimal(0) : boq.getReviewTotal();
            summaryBoq.setChangeEndAmount(amount.add(changeAmount));
            summaryBoq.setChangeEndTotal(total.add(changeTotal));
            summaryBoq.setIsApprove(model.getIsApprove());
            summaryBoq.setCreateBy(model.getUserName());
            summaryBoq.setCreateTime(model.getSummaryDate());
            summaryBoqList.add(summaryBoq);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("3.2 初始化汇总工程量清单耗时：" + (endTime - startTime) + " ms");
    }

    /**
     * 3.3 更新汇总工程量清单 更新上期末数量、金额，本期数量、金额，本期末数量、金额
     * @param summaryBoqList 汇总工程量清单集合
     * @param model 汇总实体对象
     * @param hundredItemMap 百章集合
     * @param leafNodeItemMap 叶子节点清单集合
     */
    private void updateSummaryBoq(List<SummaryBoq> summaryBoqList, SummaryVo model, Map<String, SummaryBoq> hundredItemMap, Map<String, SummaryBoq> leafNodeItemMap) {
        long startTime = System.currentTimeMillis();
        // 上期汇总工程量清单集合
        List<SummaryBoq> lastSummaryBoqList = new ArrayList<>();
        // 转成map对象
        Map<String, SummaryBoq> lastSummaryBoqMap = new HashMap<>(lastSummaryBoqList.size());
        if (!"0".equals(model.getLastPeriodName())) {
            SummaryBoq searchLast = new SummaryBoq();
            searchLast.setInstitutionCode(model.getInstitutionCode());
            searchLast.setPeriodName(model.getLastPeriodName());
            searchLast.setCreateBy(model.getApproveUser());
            lastSummaryBoqList = summaryBoqMapper.selectModelList(searchLast);
            for (SummaryBoq summaryBoq : lastSummaryBoqList) {
                lastSummaryBoqMap.put(summaryBoq.getInstitutionBoqCode(), summaryBoq);
            }
        }
        // 本期计量数量、金额集合
        List<EngMeterageContract> currentPeriodMeterageList = meterageContractMapper.selectSumMeterageList(model.getUserName(),
                model.getInstitutionCode(), model.getPeriodName());
        // 转成map对象
        Map<String, EngMeterageContract> currentPeriodMeterageMap = new HashMap<>(currentPeriodMeterageList.size());
        for (EngMeterageContract meterage: currentPeriodMeterageList) {
            currentPeriodMeterageMap.put(meterage.getBoqCode(), meterage);
        }
        // 处理上期末数量和金额，本期数量和金额，本期末数量和金额
        for (SummaryBoq summaryBoq : summaryBoqList) {
            BigDecimal lastPeriodAmount = BigDecimal.valueOf(0);
            BigDecimal lastPeriodTotal = BigDecimal.valueOf(0);
            BigDecimal currentPeriodAmount = BigDecimal.valueOf(0);
            BigDecimal currentPeriodTotal = BigDecimal.valueOf(0);
            BigDecimal currentEndPeriodAmount = BigDecimal.valueOf(0);
            BigDecimal currentEndPeriodTotal = BigDecimal.valueOf(0);
            // 更新上期数据
            SummaryBoq lastSummaryBoq = lastSummaryBoqMap.get(summaryBoq.getInstitutionBoqCode());
            if (StringUtils.isNotNull(lastSummaryBoq)) {
                lastPeriodAmount = lastSummaryBoq.getCurrentEndPeriodAmount() == null ? BigDecimal.valueOf(0) : lastSummaryBoq.getCurrentEndPeriodAmount();
                lastPeriodTotal = lastSummaryBoq.getCurrentEndPeriodTotal() == null ? BigDecimal.valueOf(0) : lastSummaryBoq.getCurrentEndPeriodTotal();
            }
            summaryBoq.setLastPeriodAmount(lastPeriodAmount);
            summaryBoq.setLastPeriodTotal(lastPeriodTotal);
            // 更新本期数据
            for (EngMeterageContract meterage: currentPeriodMeterageList) {
                BigDecimal cpa = meterage.getAmount() == null ? BigDecimal.valueOf(0) : meterage.getAmount();
                BigDecimal cpt = meterage.getTotal() == null ? BigDecimal.valueOf(0) : meterage.getTotal().setScale(summaryBoq.getDecimalPlace(), BigDecimal.ROUND_HALF_UP);
                if (meterage.getBoqCode().equals(summaryBoq.getBoqCode())) {
                    // 如果清单编号相同，则直接赋值
                    currentPeriodAmount = cpa;
                    currentPeriodTotal = cpt;
                } else if (meterage.getAncestors().contains(summaryBoq.getBoqCode() + ",")){
                    // 如果是父项，需要累加金额
                    currentPeriodTotal = currentPeriodTotal.add(cpt);
                }
            }
            summaryBoq.setCurrentPeriodAmount(currentPeriodAmount);
            summaryBoq.setCurrentPeriodTotal(currentPeriodTotal);
            if (currentPeriodTotal.compareTo(BigDecimal.ZERO) == 0) {
                summaryBoq.setCurrentPeriodFlag(Constants.NO);
            } else {
                summaryBoq.setCurrentPeriodFlag(Constants.YES);
            }
            // 更新本期末数据
            currentEndPeriodAmount = lastPeriodAmount.add(currentPeriodAmount);
            currentEndPeriodTotal = lastPeriodTotal.add(currentPeriodTotal);
            summaryBoq.setCurrentEndPeriodAmount(currentEndPeriodAmount);
            summaryBoq.setCurrentEndPeriodTotal(currentEndPeriodTotal);
            // 计算百分比
            if (Constants.YES.equals(summaryBoq.getLeafNode())) {
                BigDecimal changeEndAmount = summaryBoq.getChangeEndAmount() == null ? BigDecimal.ZERO : summaryBoq.getChangeEndAmount();
                if (changeEndAmount.compareTo(BigDecimal.ZERO) != 0
                        && StringUtils.isNotNull(summaryBoq.getCurrentEndPeriodAmount())
                        && summaryBoq.getCurrentEndPeriodAmount().compareTo(new BigDecimal(0)) != 0) {
                    int ratio = summaryBoq.getCurrentEndPeriodAmount().divide(summaryBoq.getChangeEndAmount(),
                            BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100.00)).intValue();
                    summaryBoq.setRatio(ratio);
                }
            }
            if (summaryBoq.getLevel() == 1) {
                hundredItemMap.put(summaryBoq.getBoqCode(), summaryBoq);
            }
            if (Constants.YES.equals(summaryBoq.getLeafNode())) {
                leafNodeItemMap.put(summaryBoq.getBoqCode(), summaryBoq);
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("3.3 更新汇总工程量清单 更新上期末数量、金额，本期数量、金额，本期末数量、金额耗时：" + (endTime - startTime) + " ms");
    }

    /**
     * 4.汇总工程计量清单
     *
     * @param model 汇总实体对象
     * @param leafNodeItemMap 叶子节点清单集合
     */
    private void summaryBoqMeterage(SummaryVo model, Map<String, SummaryBoq> leafNodeItemMap) {
        long startTime = System.currentTimeMillis();
        // 删除汇总工程计量清单
        summaryBoqMeterageMapper.deleteSummaryBoqMeterage(model.getInstitutionCode(), model.getPeriodName(), model.getUserName());
        // 获取计量明细
        List<EngMeterageContract> meterageList = meterageContractMapper.selectContractAndChangeList(model.getInstitutionCode(), model.getPeriodName(), model.getUserName());
        if (StringUtils.isNotNull(meterageList) && meterageList.size() > 0) {
            ProInstitution institution = institutionMapper.getModelByInnerCode(model.getInstitutionCode());
            Map<String, String> alreadyAddBoq = new HashMap<>();
            List<SummaryBoqMeterage> summaryBoqMeterageList = new ArrayList<>();
            int serialNumber = 1;
            String serialNumberTextPrefix = institution.getInstitutionCode() + "-" + model.getPeriodNameZeroFilling() + "-";
            for (EngMeterageContract meterage : meterageList) {
                String boqCode = meterage.getBoqCode();
                String value = alreadyAddBoq.get(boqCode);
                // 添加计量清单的父项工程量清单
                if (StringUtils.isEmpty(value)) {
                    SummaryBoq summaryBoq = leafNodeItemMap.get(boqCode);
                    SummaryBoqMeterage summaryBoqMeterageParent = createSummaryBoqMeterage(model, summaryBoq);
                    summaryBoqMeterageList.add(summaryBoqMeterageParent);
                    alreadyAddBoq.put(boqCode, summaryBoq.getBoqName());
                }
                // 添加计量清单
                SummaryBoqMeterage summaryBoqMeterage = createSummaryBoqMeterage(model, meterage, serialNumber, serialNumberTextPrefix);
                summaryBoqMeterageList.add(summaryBoqMeterage);
                serialNumber++;
            }
            // 批量插入
            summaryBoqMeterageMapper.insertBatch(summaryBoqMeterageList);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("汇总工程计量清单耗时：" + (endTime - startTime) + " ms");
    }

    private SummaryBoqMeterage createSummaryBoqMeterage(SummaryVo model, SummaryBoq summaryBoq) {
        SummaryBoqMeterage summaryBoqMeterage = new SummaryBoqMeterage();
        summaryBoqMeterage.setInstitutionCode(model.getInstitutionCode());
        summaryBoqMeterage.setPeriodName(model.getPeriodName());
        summaryBoqMeterage.setInstitutionBoqCode(summaryBoq.getInstitutionBoqCode());
        summaryBoqMeterage.setBoqCode(summaryBoq.getBoqCode());
        summaryBoqMeterage.setBoqCodeAlias(summaryBoq.getBoqCode());
        summaryBoqMeterage.setBoqName(summaryBoq.getBoqName());
        summaryBoqMeterage.setBoqNameAlias(summaryBoq.getBoqName());
        summaryBoqMeterage.setUnit(summaryBoq.getUnit());
        summaryBoqMeterage.setUnitAlias(summaryBoq.getUnit());
        summaryBoqMeterage.setAncestors(summaryBoq.getAncestors());
        summaryBoqMeterage.setAmount(summaryBoq.getCurrentPeriodAmount());
        summaryBoqMeterage.setBoqType(0);
        summaryBoqMeterage.setIsApprove(model.getIsApprove());
        summaryBoqMeterage.setCreateBy(model.getUserName());
        summaryBoqMeterage.setCreateTime(model.getSummaryDate());
        return summaryBoqMeterage;
    }

    private SummaryBoqMeterage createSummaryBoqMeterage(SummaryVo model, EngMeterageContract meterage, int serialNumber, String serialNumberTextPrefix) {
        SummaryBoqMeterage summaryBoqMeterage = new SummaryBoqMeterage();
        summaryBoqMeterage.setInstitutionCode(model.getInstitutionCode());
        summaryBoqMeterage.setPeriodName(model.getPeriodName());
        summaryBoqMeterage.setMeterageBoqCode(meterage.getMeterageBoqCode());
        summaryBoqMeterage.setBoqCode(meterage.getBoqCode());
        summaryBoqMeterage.setBoqCodeAlias("");
        summaryBoqMeterage.setBoqName(meterage.getBoqName());
        summaryBoqMeterage.setUnit(meterage.getUnit());
        summaryBoqMeterage.setUnitAlias("");
        summaryBoqMeterage.setAncestors(meterage.getAncestors());
        summaryBoqMeterage.setAmount(meterage.getAmount());
        summaryBoqMeterage.setTotal(meterage.getTotal());
        String beginStation = meterage.getBeginStation();
        summaryBoqMeterage.setBeginStation(beginStation);
        String endStation = meterage.getEndStation();
        summaryBoqMeterage.setEndStation(endStation);
        String beginEndStation = beginStation;
        if (StringUtils.isNotEmpty(endStation)) {
            beginEndStation = beginStation + "~" + endStation;
        }
        summaryBoqMeterage.setBeginEndStation(beginEndStation);
        summaryBoqMeterage.setBoqNameAlias(beginEndStation);
        summaryBoqMeterage.setPlace(meterage.getPlace());
        summaryBoqMeterage.setItem(meterage.getItem());
        summaryBoqMeterage.setFormula(meterage.getFormula());
        summaryBoqMeterage.setBlueprint(meterage.getBlueprint());
        summaryBoqMeterage.setCertificateNo(meterage.getCertificateNo());
        // 重置草图路径
        String filePath = meterage.getFilePath();
        if (StringUtils.isNotEmpty(filePath)) {
            String physicalPath = MasterConfig.getProfile() + filePath.substring(Constants.RESOURCE_PREFIX.length());
            System.out.println("物理路径：" + physicalPath);
            if (StringUtils.isNotEmpty(physicalPath)) {
                summaryBoqMeterage.setSketchPath(physicalPath);
            }
        }
        summaryBoqMeterage.setMeterageType(meterage.getIsEdit());
        summaryBoqMeterage.setBoqType(1);
        summaryBoqMeterage.setSerialNumber(serialNumber);
        if (serialNumber < 10) {
            summaryBoqMeterage.setSerialNumberText(serialNumberTextPrefix + "00" + serialNumber);
        } else if (serialNumber < 100){
            summaryBoqMeterage.setSerialNumberText(serialNumberTextPrefix + "0" + serialNumber);
        } else {
            summaryBoqMeterage.setSerialNumberText(serialNumberTextPrefix + serialNumber);
        }
        summaryBoqMeterage.setIsApprove(model.getIsApprove());
        summaryBoqMeterage.setCreateBy(model.getUserName());
        summaryBoqMeterage.setCreateTime(model.getSummaryDate());
        return summaryBoqMeterage;
    }

    /**
     * 5.汇总中期支付证书
     *
     * @param model 汇总实体对象
     * @param hundredItemMap 百章清单集合
     * @param summaryBoqList 汇总清单集合
     */
    private void summaryIpc(SummaryVo model, Map<String, SummaryBoq> hundredItemMap, List<SummaryBoq> summaryBoqList) {
        long startTime = System.currentTimeMillis();
        // 删除数据
        summaryIpcMapper.deleteSummaryIpc(model.getUserName(), model.getInstitutionCode(), model.getPeriodName());
        // 获取标段
        ProInstitution institution = institutionMapper.getModelByInnerCode(model.getInstitutionCode());
        ProInstitutionDetail institutionDetail = institutionDetailMapper.getModelByInnerCode(model.getInstitutionCode());
        // 获取项目支付项目
        ProPaymentItems search = new ProPaymentItems();
        search.setProjectId(institution.getProjectId());
        search.setItemStatus(Constants.SUCCESS);
        List<ProPaymentItems> paymentItems = paymentItemsMapper.selectModelList(search);
        List<SummaryIpc> ipcList = new ArrayList<>();
        // 5.1 初始化中期支付证书
        initSummaryIpc(model, paymentItems, ipcList);
        // 5.2 更新百章合同金额,复核金额，变更金额，变更后金额，上期末金额，本期金额，本期末金额
        updateSummaryIpcHundredItem(ipcList, hundredItemMap);
        // 5.4 更新其他支付项目的合同金额 暂定金
        updateSummaryIpcContractTotal(ipcList, institutionDetail);
        // 5.5 更新其他支付项目的上期末金额，本期金额，本期末金额
        updateSummaryIpcTotal(model, ipcList, institutionDetail);
        // 5.5.1 110黄河大桥项目分大桥，小桥
        if (institution.getProjectId() == 3) {
            insertG110YellowBridge(model, ipcList, institution, summaryBoqList);
        }
        // 5.6 更新本期完成百分比和本期末完成百分比
        updateSummaryIpcRatio(ipcList);
        summaryIpcMapper.insertBatch(ipcList);
        long endTime = System.currentTimeMillis();
        System.out.println("汇总中期支付证书耗时：" + (endTime - startTime) + " ms");
    }

    /**
     * 5.1 初始化中期支付证书
     *
     * @param model 汇总实体对象
     * @param paymentItems 支付项目
     * @param ipcList 中期支付证书集合
     */
    private void initSummaryIpc(SummaryVo model, List<ProPaymentItems> paymentItems, List<SummaryIpc> ipcList) {
        // 初始化中期支付证书 支付项目
        for (ProPaymentItems paymentItem : paymentItems) {
            SummaryIpc ipc = new SummaryIpc();
            ipc.setInstitutionCode(model.getInstitutionCode());
            ipc.setPeriodName(model.getPeriodName());
            ipc.setItemCode(paymentItem.getItemCode());
            ipc.setItemName(paymentItem.getItemName());
            ipc.setItemOrder(paymentItem.getItemOrder());
            ipc.setSign(paymentItem.getSign());
            ipc.setComputeMode(paymentItem.getComputeMode());
            ipc.setHundredItem(paymentItem.getHundredItem());
            ipc.setSumItem(paymentItem.getSumItem());
            ipc.setPercentageItem(paymentItem.getPercentageItem());
            ipc.setRatio(paymentItem.getRatio());
            ipc.setTotal(new BigDecimal(0));
            ipc.setReviewTotal(new BigDecimal(0));
            ipc.setChangeTotal(new BigDecimal(0));
            ipc.setChangeEndTotal(new BigDecimal(0));
            ipc.setLastPeriodTotal(new BigDecimal(0));
            ipc.setCurrentPeriodTotal(new BigDecimal(0));
            ipc.setCurrentEndPeriodTotal(new BigDecimal(0));
            ipc.setFinishRatio(0);
            ipc.setIsApprove(model.getIsApprove());
            ipc.setCreateBy(model.getUserName());
            ipc.setCreateTime(model.getSummaryDate());
            ipcList.add(ipc);
        }
    }

    /**
     * 5.2 更新百章合同金额,复核金额，变更金额，变更后金额，上期末金额，本期金额，本期末金额
     *
     * @param ipcList 中期支付证书集合
     * @param hundredItemMap 百章集合
     */
    private void updateSummaryIpcHundredItem(List<SummaryIpc> ipcList, Map<String, SummaryBoq> hundredItemMap) {
        BigDecimal boqSumTotal = BigDecimal.valueOf(0);
        BigDecimal boqSumReviewTotal = BigDecimal.valueOf(0);
        BigDecimal boqSumChangeTotal = BigDecimal.valueOf(0);
        BigDecimal boqSumChangeEndTotal = BigDecimal.valueOf(0);
        BigDecimal boqSumLastPeriodTotal = BigDecimal.valueOf(0);
        BigDecimal boqSumCurrentPeriodTotal = BigDecimal.valueOf(0);
        BigDecimal boqSumCurrentEndPeriodTotal = BigDecimal.valueOf(0);
        for (SummaryIpc ipc : ipcList) {
            if (ipc.getComputeMode() == 1) {
                SummaryBoq summaryBoq = hundredItemMap.get(ipc.getHundredItem());
                if (StringUtils.isNotNull(summaryBoq)) {
                    // 合同金额
                    BigDecimal total = summaryBoq.getTotal() == null ? BigDecimal.valueOf(0) : summaryBoq.getTotal();
                    ipc.setTotal(total);
                    boqSumTotal = boqSumTotal.add(total.setScale(6, BigDecimal.ROUND_HALF_UP));
                    // 复核金额
                    BigDecimal reviewTotal = summaryBoq.getReviewTotal() == null ? BigDecimal.valueOf(0) : summaryBoq.getReviewTotal();
                    ipc.setReviewTotal(reviewTotal);
                    boqSumReviewTotal = boqSumReviewTotal.add(reviewTotal.setScale(6, BigDecimal.ROUND_HALF_UP));
                    // 变更金额
                    BigDecimal changeTotal = summaryBoq.getChangeTotal() == null ? BigDecimal.valueOf(0) : summaryBoq.getChangeTotal();
                    ipc.setChangeTotal(changeTotal);
                    boqSumChangeTotal = boqSumChangeTotal.add(changeTotal.setScale(6, BigDecimal.ROUND_HALF_UP));
                    // 变更后金额
                    BigDecimal changeEndTotal = summaryBoq.getChangeEndTotal() == null ? BigDecimal.valueOf(0) : summaryBoq.getChangeEndTotal();
                    ipc.setChangeEndTotal(changeEndTotal);
                    boqSumChangeEndTotal = boqSumChangeEndTotal.add(changeEndTotal.setScale(6, BigDecimal.ROUND_HALF_UP));
                    // 上期末金额
                    BigDecimal lastPeriodTotal = summaryBoq.getLastPeriodTotal() == null ? BigDecimal.valueOf(0) : summaryBoq.getLastPeriodTotal();
                    ipc.setLastPeriodTotal(lastPeriodTotal);
                    boqSumLastPeriodTotal = boqSumLastPeriodTotal.add(lastPeriodTotal.setScale(6, BigDecimal.ROUND_HALF_UP));
                    // 本期金额
                    BigDecimal currentPeriodTotal = summaryBoq.getCurrentPeriodTotal() == null ? BigDecimal.valueOf(0) : summaryBoq.getCurrentPeriodTotal();
                    ipc.setCurrentPeriodTotal(currentPeriodTotal);
                    boqSumCurrentPeriodTotal = boqSumCurrentPeriodTotal.add(currentPeriodTotal.setScale(6, BigDecimal.ROUND_HALF_UP));
                    // 本期末金额
                    BigDecimal currentEndPeriodTotal = summaryBoq.getCurrentEndPeriodTotal() == null ? BigDecimal.valueOf(0) : summaryBoq.getCurrentEndPeriodTotal();
                    ipc.setCurrentEndPeriodTotal(currentEndPeriodTotal);
                    boqSumCurrentEndPeriodTotal = boqSumCurrentEndPeriodTotal.add(currentEndPeriodTotal.setScale(6, BigDecimal.ROUND_HALF_UP));
                }
            }

            // 清单小计
            if (PaymentConstant.ZQZFZS_QDXJ.equals(ipc.getItemCode())) {
                ipc.setTotal(boqSumTotal);
                ipc.setReviewTotal(boqSumReviewTotal);
                ipc.setChangeTotal(boqSumChangeTotal);
                ipc.setChangeEndTotal(boqSumChangeEndTotal);
                ipc.setLastPeriodTotal(boqSumLastPeriodTotal);
                ipc.setCurrentPeriodTotal(boqSumCurrentPeriodTotal);
                ipc.setCurrentEndPeriodTotal(boqSumCurrentEndPeriodTotal);
            }

        }
    }

    /**
     * 5.4 更新其他支付项目的合同金额 暂定金
     *
     * @param ipcList 中期支付证书集合
     * @param institutionDetail 标段详情
     */
    private void updateSummaryIpcContractTotal(List<SummaryIpc> ipcList, ProInstitutionDetail institutionDetail) {
        for (SummaryIpc ipc : ipcList) {
            if (PaymentConstant.ZQZFZS_ZXZDJ.equals(ipc.getItemCode())) {
                if (StringUtils.isNotNull(institutionDetail)) {
                    BigDecimal provisionalDepositTotal = institutionDetail.getProvisionalDepositTotal() == null ? BigDecimal.valueOf(0) : institutionDetail.getProvisionalDepositTotal();
                    ipc.setTotal(provisionalDepositTotal);
                    ipc.setReviewTotal(provisionalDepositTotal);
                    ipc.setChangeEndTotal(provisionalDepositTotal);
                }
            }
        }
    }

    /**
     * 5.5 更新其他支付项目的上期末金额，本期金额，本期末金额
     *
     * @param model 汇总实体对象
     * @param ipcList 中期支付证书集合
     * @param institutionDetail 标段详情
     */
    private void updateSummaryIpcTotal(SummaryVo model, List<SummaryIpc> ipcList, ProInstitutionDetail institutionDetail) {
        System.out.println(model.getLastPeriodName());
        // 取出上期数据
        SummaryIpc lastSearch = new SummaryIpc();
        lastSearch.setInstitutionCode(model.getInstitutionCode());
        lastSearch.setPeriodName(model.getLastPeriodName());
        lastSearch.setCreateBy(model.getApproveUser());
        List<SummaryIpc> lastIpcList = summaryIpcMapper.selectModelList(lastSearch);
        Map<String, SummaryIpc> lastIpcMap = new HashMap<>(lastIpcList.size());
        Map<String, SummaryIpc> ipcMap = new HashMap<>(lastIpcList.size());
        // 获取固定值数据
        EngMeterageOther searchOther = new EngMeterageOther();
        searchOther.setItemName(model.getInstitutionCode());
        searchOther.setItemCode(model.getPeriodName());
        searchOther.setUser(model.getUserName());
        List<EngMeterageOther> otherList = meterageOtherMapper.selectModelListBySummary(searchOther);
        // 转map
        for (SummaryIpc ipc : lastIpcList) {
            lastIpcMap.put(ipc.getItemCode(), ipc);
        }
        // 循环处理
        for (SummaryIpc ipc : ipcList) {
            // 上期末金额
            if (ipc.getComputeMode() != 1) {
                if (!"0".equals(model.getLastPeriodName())) {
                    SummaryIpc lastIpc = lastIpcMap.get(ipc.getItemCode());
                    if (StringUtils.isNull(lastIpc)) {
                        ipc.setLastPeriodTotal(BigDecimal.valueOf(0));
                    } else {
                        ipc.setLastPeriodTotal(lastIpc.getCurrentEndPeriodTotal());
                    }
                } else {
                    ipc.setLastPeriodTotal(BigDecimal.valueOf(0));
                }
            }
            // 本期金额、本期末金额
            if (ipc.getComputeMode() == 4) {
                // 本期金额、本期末金额--固定值
                updateSummaryIpcFixedValue(ipc, otherList);
            } else if (ipc.getComputeMode() == 5) {
                // 本期金额、本期末金额--其他方式
                updateSummaryIpcOther(ipc, institutionDetail, ipcMap);
            } else if (ipc.getComputeMode() == 3) {
                // 本期金额、本期末金额--百分比
                updateSummaryIpcPercentage(ipc, ipcMap);
            } else if (ipc.getComputeMode() == 2 && !PaymentConstant.ZQZFZS_QDXJ.equals(ipc.getItemCode())) {
                // 本期金额、本期末金额--合计, 清单小计 在前面已经计算过
                updateSummaryIpcTotal(ipc, ipcMap);
            }
            ipcMap.put(ipc.getItemCode(), ipc);
        }
    }

    /**
     * 中期支付证书固定值更新
     *
     * @param ipc 中期支付证书支付项目
     * @param otherList 固定值集合
     */
    private void updateSummaryIpcFixedValue(SummaryIpc ipc, List<EngMeterageOther> otherList) {
        // 避免标段本期没有做工程计量，空汇总导致固定值为空无法赋值问题，所以先进行一次0值赋值。
        ipc.setCurrentPeriodTotal(BigDecimal.valueOf(0));
        BigDecimal lastTotal = ipc.getLastPeriodTotal() == null ? BigDecimal.valueOf(0) : ipc.getLastPeriodTotal();
        ipc.setCurrentEndPeriodTotal(lastTotal.add(BigDecimal.valueOf(0)));
        for (EngMeterageOther other : otherList) {
            if (other.getItemCode().equals(ipc.getItemCode())) {
                BigDecimal fixedValue = other.getTotal() == null ? BigDecimal.valueOf(0) : other.getTotal();
                BigDecimal lastPeriodTotal = ipc.getLastPeriodTotal() == null ? BigDecimal.valueOf(0) : ipc.getLastPeriodTotal();
                ipc.setCurrentPeriodTotal(fixedValue);
                ipc.setCurrentEndPeriodTotal(lastPeriodTotal.add(fixedValue));
            }
        }
    }

    /**
     * 中期支付证书其他更新 -- 扣回动员预付款
     *
     * @param ipc 中期支付证书支付项目
     * @param institutionDetail 标段详情
     */
    private void updateSummaryIpcOther (SummaryIpc ipc, ProInstitutionDetail institutionDetail, Map<String, SummaryIpc> ipcMap) {
        if (PaymentConstant.ZQZFZS_KHDYYFK.equals(ipc.getItemCode())) {
            updateSummaryIpcMobilizationAdvancePayment(ipc, institutionDetail, ipcMap);
        } else if (PaymentConstant.ZQZFZS_BZJ.equals(ipc.getItemCode())) {
            updateSummaryIpcRetentionMoney(ipc, institutionDetail, ipcMap);
        }
    }

    /**
     * 扣回动员预付款 超过动员预付款起扣金额的部分，每完成合同总价的1%，扣除动员预付款的2%
     *
     * @param ipc 扣回动员预付款支付项目
     * @param institutionDetail 标段详情
     * @param ipcMap 支付项目map集合
     */
    private void updateSummaryIpcMobilizationAdvancePayment(SummaryIpc ipc, ProInstitutionDetail institutionDetail, Map<String, SummaryIpc> ipcMap) {
        // 合同金额
        BigDecimal contractTotal = institutionDetail.getContractTotal() == null ? BigDecimal.valueOf(0) : institutionDetail.getContractTotal();
        System.out.println("合同金额：" + contractTotal);
        // 动员预付款起扣比例
        int advancePaymentBegin = institutionDetail.getAdvancePaymentBegin() == null ? 0 : institutionDetail.getAdvancePaymentBegin();
        System.out.println("起扣比例：" + advancePaymentBegin);
        // 动员预付款起扣金额
        BigDecimal advancePaymentStartTotal = contractTotal.multiply(BigDecimal.valueOf(advancePaymentBegin)).divide(BigDecimal.valueOf(100), BigDecimal.ROUND_HALF_UP);
        System.out.println("起扣金额：" + advancePaymentStartTotal);
        // 本期末清单小计
        BigDecimal currentEndPeriodBoqSumTotal = ipcMap.get(PaymentConstant.ZQZFZS_QDXJ).getCurrentEndPeriodTotal() == null ? BigDecimal.valueOf(0) : ipcMap.get(PaymentConstant.ZQZFZS_QDXJ).getCurrentEndPeriodTotal();
        System.out.println("本期末清单小计：" + currentEndPeriodBoqSumTotal);
        // 本期末清单小计大于动员付款起扣金额
        if (currentEndPeriodBoqSumTotal.compareTo(advancePaymentStartTotal) > 0) {
            // 动员预付款
            BigDecimal advancePaymentTotal = ipcMap.get(PaymentConstant.ZQZFZS_DYYFK).getCurrentEndPeriodTotal() == null ?
                    BigDecimal.valueOf(0) : ipcMap.get(PaymentConstant.ZQZFZS_DYYFK).getCurrentEndPeriodTotal();
            System.out.println("动员预付款：" + advancePaymentTotal);
            // 扣款金额
            BigDecimal deductionTotal = currentEndPeriodBoqSumTotal.subtract(advancePaymentStartTotal);
            BigDecimal mapCepTotal = deductionTotal.divide(contractTotal, 12, BigDecimal.ROUND_HALF_UP).
                    multiply(BigDecimal.valueOf(2)).
                    multiply(advancePaymentTotal).
                    setScale(6, BigDecimal.ROUND_HALF_UP);
            // 如果本期末扣回动员预付款超过本期末动员预付款，则让本期末扣回动员预付款等于本期末动员预付款
            if (mapCepTotal.compareTo(advancePaymentTotal) > 0) {
                mapCepTotal = advancePaymentTotal;
            }
            BigDecimal lastPeriodTotal = ipc.getLastPeriodTotal() == null ? BigDecimal.valueOf(0) : ipc.getLastPeriodTotal();
            BigDecimal currentPeriodTotal = mapCepTotal.subtract(lastPeriodTotal);
            ipc.setCurrentPeriodTotal(currentPeriodTotal);
            ipc.setCurrentEndPeriodTotal(mapCepTotal);
        }
    }

    /**
     * 保留金
     *
     * @param ipc 扣回动员预付款支付项目
     * @param institutionDetail 标段详情
     * @param ipcMap 支付项目map集合
     */
    private void updateSummaryIpcRetentionMoney(SummaryIpc ipc, ProInstitutionDetail institutionDetail, Map<String, SummaryIpc> ipcMap) {
        BigDecimal contractTotal = institutionDetail.getContractTotal() == null ? BigDecimal.valueOf(0) : institutionDetail.getContractTotal();
        BigDecimal currentEndPeriodBoqSumTotal = ipcMap.get(PaymentConstant.ZQZFZS_QDXJ).getCurrentEndPeriodTotal() == null ? BigDecimal.valueOf(0) : ipcMap.get("QDXJ").getCurrentEndPeriodTotal();
        // 保留金扣款比例
        int retentionMoneyDeduction = institutionDetail.getRetentionMoneyDeduction();
        BigDecimal rmCepTotal = currentEndPeriodBoqSumTotal.
                multiply(BigDecimal.valueOf(retentionMoneyDeduction)).
                divide(BigDecimal.valueOf(100), 6, BigDecimal.ROUND_HALF_UP).setScale(6, BigDecimal.ROUND_HALF_UP);
        // 保留金限额比例
        int retentionMoneyQuota = institutionDetail.getRetentionMoneyQuota();
        BigDecimal rmQuotaTotal = contractTotal.
                multiply(BigDecimal.valueOf(retentionMoneyQuota)).
                divide(BigDecimal.valueOf(100), 6, BigDecimal.ROUND_HALF_UP).setScale(6, BigDecimal.ROUND_HALF_UP);
        // 如果扣款金额大于限额金额，则直接等于限额金额
        if (rmCepTotal.compareTo(rmQuotaTotal) > 0) {
            rmCepTotal = rmQuotaTotal;
        }
        BigDecimal lastPeriodTotal = ipc.getLastPeriodTotal() == null ? BigDecimal.valueOf(0) : ipc.getLastPeriodTotal();
        BigDecimal currentPeriodTotal = rmCepTotal.subtract(lastPeriodTotal);
        ipc.setCurrentPeriodTotal(currentPeriodTotal);
        ipc.setCurrentEndPeriodTotal(rmCepTotal);

    }

    /**
     * 中期支付证书比例值更新
     *
     * @param ipc 中期支付证书支付项目
     * @param ipcMap 中期支付证书支付项目map集合
     */
    private void updateSummaryIpcPercentage(SummaryIpc ipc, Map<String, SummaryIpc> ipcMap) {
        // 百分比项目， 百分比
        String percentageItem = ipc.getPercentageItem();
        BigDecimal ratio = ipc.getRatio() == null ? BigDecimal.valueOf(0) : ipc.getRatio();
        if (StringUtils.isNotEmpty(percentageItem) && ratio.compareTo(BigDecimal.valueOf(0)) > 0) {
            SummaryIpc percentageIpc = ipcMap.get(percentageItem);
            if (StringUtils.isNotNull(percentageIpc)) {
                BigDecimal percentageTotal = percentageIpc.getCurrentPeriodTotal() == null ? BigDecimal.valueOf(0) : percentageIpc.getCurrentPeriodTotal();
                BigDecimal currentPeriodTotal = percentageTotal.multiply(ratio).divide(BigDecimal.valueOf(100), 6, BigDecimal.ROUND_HALF_UP).setScale(6, BigDecimal.ROUND_HALF_UP);
                BigDecimal lastPeriodTotal = ipc.getLastPeriodTotal() == null ? BigDecimal.valueOf(0) : ipc.getLastPeriodTotal();
                BigDecimal currentEndPeriodTotal = lastPeriodTotal.add(currentPeriodTotal);
                ipc.setCurrentPeriodTotal(currentPeriodTotal);
                ipc.setCurrentEndPeriodTotal(currentEndPeriodTotal);
            }
        }
    }

    /**
     * 中期支付证书合计值更新
     *
     * @param ipc 中期支付证书支付项目
     * @param ipcMap 中期支付证书支付项目map集合
     */
    private void updateSummaryIpcTotal(SummaryIpc ipc, Map<String, SummaryIpc> ipcMap) {
        String sumItem = ipc.getSumItem();
        if (StringUtils.isNotEmpty(sumItem)) {
            BigDecimal total = BigDecimal.valueOf(0);
            BigDecimal reviewTotal = BigDecimal.valueOf(0);
            BigDecimal changeTotal = BigDecimal.valueOf(0);
            BigDecimal changeEndTotal = BigDecimal.valueOf(0);
            BigDecimal currentPeriodTotal = BigDecimal.valueOf(0);
            String[] itemArray = sumItem.split(",");
            for (String item: itemArray) {
                SummaryIpc itemIpc = ipcMap.get(item);
                if (StringUtils.isNotNull(itemIpc)) {
                    // 合同金额
                    BigDecimal itemTotal = itemIpc.getTotal() == null ? BigDecimal.valueOf(0) : itemIpc.getTotal();
                    total = total.add(itemTotal.multiply(itemIpc.getSign()));
                    // 复核金额
                    BigDecimal itemReviewTotal = itemIpc.getReviewTotal() == null ? BigDecimal.valueOf(0) : itemIpc.getReviewTotal();
                    reviewTotal = reviewTotal.add(itemReviewTotal.multiply(itemIpc.getSign()));
                    // 变更金额
                    BigDecimal itemChangeTotal = itemIpc.getChangeTotal() == null ? BigDecimal.valueOf(0) : itemIpc.getChangeTotal();
                    changeTotal = changeTotal.add(itemChangeTotal.multiply(itemIpc.getSign()));
                    // 变更后金额
                    BigDecimal itemChangeEndTotal = itemIpc.getChangeEndTotal() == null ? BigDecimal.valueOf(0) : itemIpc.getChangeEndTotal();
                    changeEndTotal = changeEndTotal.add(itemChangeEndTotal.multiply(itemIpc.getSign()));
                    // 本期金额
                    BigDecimal itemCurrentPeriodTotal = itemIpc.getCurrentPeriodTotal() == null ? BigDecimal.valueOf(0) : itemIpc.getCurrentPeriodTotal();
                    currentPeriodTotal = currentPeriodTotal.add(itemCurrentPeriodTotal.multiply(itemIpc.getSign()));
                }
            }
            BigDecimal lastPeriodTotal = ipc.getLastPeriodTotal() == null ? BigDecimal.valueOf(0) : ipc.getLastPeriodTotal();
            ipc.setCurrentPeriodTotal(currentPeriodTotal);
            BigDecimal currentEndPeriodTotal = lastPeriodTotal.add(currentPeriodTotal);
            ipc.setCurrentEndPeriodTotal(currentEndPeriodTotal);
            ipc.setTotal(total);
            ipc.setReviewTotal(reviewTotal);
            ipc.setChangeTotal(changeTotal);
            ipc.setChangeEndTotal(changeEndTotal);
        }
    }

    /**
     * 5.6 更新本期完成百分比和本期末完成百分比
     *
     * @param ipcList 中期支付证书 支付项目集合
     */
    private void updateSummaryIpcRatio(List<SummaryIpc> ipcList) {
        for (SummaryIpc ipc : ipcList) {
            Integer finishRatio = calRatio(ipc.getCurrentEndPeriodTotal(), ipc.getChangeEndTotal());
            ipc.setFinishRatio(finishRatio);
            Integer currentFinishRatio = calRatio(ipc.getCurrentPeriodTotal(), ipc.getChangeEndTotal());
            ipc.setCurrentFinishRatio(currentFinishRatio);
        }
    }

    /**
     * 计算比例
     *
     * @param val1 值1
     * @param val2 值2
     * @return 比例
     */
    private Integer calRatio(BigDecimal val1, BigDecimal val2) {
        if (StringUtils.isNotNull(val2) && val2.compareTo(BigDecimal.valueOf(0)) != 0) {
            if (StringUtils.isNotNull(val1) && val1.compareTo(BigDecimal.valueOf(0)) != 0) {
                BigDecimal ratio1 = val1.divide(val2,6, BigDecimal.ROUND_HALF_UP);
                BigDecimal ratio2 = ratio1.multiply(BigDecimal.valueOf(100));
                int ratio3 = ratio2.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                return ratio3;
            }
        }
        return null;
    }

    /**
     * 110黄河大桥插入大桥和小桥支付项目
     *
     * @param model 汇总
     * @param ipcList ipc集合
     * @param institution 标段
     * @param summaryBoqList 汇总清单集合
     */
    private void insertG110YellowBridge(SummaryVo model, List<SummaryIpc> ipcList, ProInstitution institution, List<SummaryBoq> summaryBoqList) {
        // 插入大桥,小桥
        SummaryIpc bigBridge = new SummaryIpc();
        SummaryIpc smallBridge = new SummaryIpc();
        bigBridge.setInstitutionCode(model.getInstitutionCode());
        bigBridge.setPeriodName(model.getPeriodName());
        bigBridge.setItemCode("400");
        bigBridge.setItemName("大 桥");
        bigBridge.setItemOrder(41L);
        smallBridge.setInstitutionCode(model.getInstitutionCode());
        smallBridge.setPeriodName(model.getPeriodName());
        smallBridge.setItemCode("400");
        smallBridge.setItemName("小 桥");
        smallBridge.setItemOrder(42L);
        // 合同金额
        BigDecimal total1 = BigDecimal.ZERO;
        BigDecimal reviewTotal1 = BigDecimal.ZERO;
        BigDecimal changeTotal1 = BigDecimal.ZERO;
        BigDecimal changeEndTotal1 = BigDecimal.ZERO;
        BigDecimal lastPeriodTotal1 = BigDecimal.ZERO;
        BigDecimal currentPeriodTotal1 = BigDecimal.ZERO;
        BigDecimal currentEndPeriodTotal1 = BigDecimal.ZERO;
        BigDecimal total2 = BigDecimal.ZERO;
        BigDecimal reviewTotal2 = BigDecimal.ZERO;
        BigDecimal changeTotal2 = BigDecimal.ZERO;
        BigDecimal changeEndTotal2 = BigDecimal.ZERO;
        BigDecimal lastPeriodTotal2 = BigDecimal.ZERO;
        BigDecimal currentPeriodTotal2 = BigDecimal.ZERO;
        BigDecimal currentEndPeriodTotal2 = BigDecimal.ZERO;
        for (SummaryBoq boq : summaryBoqList) {
            // 大桥 400章清单，第二级别，包含*号
            if (boq.getLevel() == 2 && boq.getAncestors().startsWith("400,") && boq.getBoqCode().contains("*")) {
                BigDecimal total3 = boq.getTotal() == null ? BigDecimal.ZERO : boq.getTotal();
                BigDecimal reviewTotal3 = boq.getReviewTotal() == null ? BigDecimal.ZERO : boq.getReviewTotal();
                BigDecimal changeTotal3 = boq.getChangeTotal() == null ? BigDecimal.ZERO : boq.getChangeTotal();
                BigDecimal changeEndTotal3 = boq.getChangeEndTotal() == null ? BigDecimal.ZERO : boq.getChangeEndTotal();
                BigDecimal lastPeriodTotal3 = boq.getLastPeriodTotal() == null ? BigDecimal.ZERO : boq.getLastPeriodTotal();
                BigDecimal currentPeriodTotal3 = boq.getCurrentPeriodTotal() == null ? BigDecimal.ZERO : boq.getCurrentPeriodTotal();
                BigDecimal currentEndPeriodTotal3 = boq.getCurrentEndPeriodTotal() == null ? BigDecimal.ZERO : boq.getCurrentEndPeriodTotal();
                total1 = total1.add(total3);
                reviewTotal1 = reviewTotal1.add(reviewTotal3);
                changeTotal1 = changeTotal1.add(changeTotal3);
                changeEndTotal1 = changeEndTotal1.add(changeEndTotal3);
                lastPeriodTotal1 = lastPeriodTotal1.add(lastPeriodTotal3);
                currentPeriodTotal1 = currentPeriodTotal1.add(currentPeriodTotal3);
                currentEndPeriodTotal1 = currentEndPeriodTotal1.add(currentEndPeriodTotal3);
            }
            // 小桥 400章清单，第二级别，不包含*号
            if (boq.getLevel() == 2 && boq.getAncestors().startsWith("400,") && !boq.getBoqCode().contains("*")) {
                BigDecimal total4 = boq.getTotal() == null ? BigDecimal.ZERO : boq.getTotal();
                BigDecimal reviewTotal4 = boq.getReviewTotal() == null ? BigDecimal.ZERO : boq.getReviewTotal();
                BigDecimal changeTotal4 = boq.getChangeTotal() == null ? BigDecimal.ZERO : boq.getChangeTotal();
                BigDecimal changeEndTotal4 = boq.getChangeEndTotal() == null ? BigDecimal.ZERO : boq.getChangeEndTotal();
                BigDecimal lastPeriodTotal4 = boq.getLastPeriodTotal() == null ? BigDecimal.ZERO : boq.getLastPeriodTotal();
                BigDecimal currentPeriodTotal4 = boq.getCurrentPeriodTotal() == null ? BigDecimal.ZERO : boq.getCurrentPeriodTotal();
                BigDecimal currentEndPeriodTotal4 = boq.getCurrentEndPeriodTotal() == null ? BigDecimal.ZERO : boq.getCurrentEndPeriodTotal();
                total2 = total2.add(total4);
                reviewTotal2 = reviewTotal2.add(reviewTotal4);
                changeTotal2 = changeTotal2.add(changeTotal4);
                changeEndTotal2 = changeEndTotal2.add(changeEndTotal4);
                lastPeriodTotal2 = lastPeriodTotal2.add(lastPeriodTotal4);
                currentPeriodTotal2 = currentPeriodTotal2.add(currentPeriodTotal4);
                currentEndPeriodTotal2 = currentEndPeriodTotal2.add(currentEndPeriodTotal4);
            }
        }
        bigBridge.setTotal(total1);
        bigBridge.setReviewTotal(reviewTotal1);
        bigBridge.setChangeTotal(changeTotal1);
        bigBridge.setChangeEndTotal(changeEndTotal1);
        bigBridge.setLastPeriodTotal(lastPeriodTotal1);
        bigBridge.setCurrentPeriodTotal(currentPeriodTotal1);
        bigBridge.setCurrentEndPeriodTotal(currentEndPeriodTotal1);
        bigBridge.setIsApprove(model.getIsApprove());
        bigBridge.setCreateBy(model.getUserName());
        bigBridge.setCreateTime(model.getSummaryDate());
        ipcList.add(bigBridge);

        smallBridge.setTotal(total2);
        smallBridge.setReviewTotal(reviewTotal2);
        smallBridge.setChangeTotal(changeTotal2);
        smallBridge.setChangeEndTotal(changeEndTotal2);
        smallBridge.setLastPeriodTotal(lastPeriodTotal2);
        smallBridge.setCurrentPeriodTotal(currentPeriodTotal2);
        smallBridge.setCurrentEndPeriodTotal(currentEndPeriodTotal2);
        smallBridge.setIsApprove(model.getIsApprove());
        smallBridge.setCreateBy(model.getUserName());
        smallBridge.setCreateTime(model.getSummaryDate());
        ipcList.add(smallBridge);
    }

}
